/*
 * Copyright 2018, 2024 UltrasonicMadness
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const INTERVAL_LENGTH = 60000; // 60000 ms = 1 minute

// Keeping track of how far through this Easter egg the user is.
let dreamStates =
{
    STARTED: 0,
    GRAY: 1,
    SEPIA: 2,
    SILENT: 3,
    SILENT_BUTTON1: 4,
    MUSIC: 5,
    MUSIC_BUTTON1: 6,
    MESSAGE: 7,
    MESSAGE2: 8,
    FINISHED: 9
};

let keysPressed; // Keeps track of which keys have been pressed.
let interval; // Used to keep track of .setInterval so that it can be cleared.
let time = 0; // How many minutes the program has been running
let currentState = dreamStates.STARTED;

const dreamcodeGray = new Event("dreamcodeGray");
const dreamcodeSepia = new Event("dreamcodeSepia");
const dreamcodeSilent = new Event("dreamcodeSilent");
const dreamcodeMusic = new Event("dreamcodeMusic");
const dreamcodeMessage = new Event("dreamcodeMessage");
const dreamcodeMessage2 = new Event("dreamcodeMessage2");
const dreamcodeFinished = new Event("dreamcodeFinished");

function initKeys() // Resets logged key presses to false
{
    keysPressed =
    {
        ArrowUp: false,
        ArrowDown: false,
        ArrowLeft: false,
        ArrowRight: false,
        a: false,
        b: false,
        Enter: false,
        Shift: false,
    };
}

// This function is run at an interval; it increments the time variable and
// triggers events depending on how long the program has been running
function incrementMinutes()
{
    time++;
    
    // Unless noted, all these do is change the state of the program.
    if (time >= 91 && currentState == dreamStates.SEPIA)
    {
        initKeys();
        currentState = dreamStates.SILENT;
        dispatchEvent(dreamcodeSilent);
        time = 0; // Reset the counter
        window.clearTimeout(interval); // Don't run this function anymore
    }
    else if (time >= 36 && currentState == dreamStates.GRAY)
    {
        initKeys();
        currentState = dreamStates.SEPIA;
        dispatchEvent(dreamcodeSepia);
    }
    else if (time >= 18 && currentState == dreamStates.STARTED)
    {
        initKeys();
        currentState = dreamStates.GRAY;
        dispatchEvent(dreamcodeGray);
    }
}

function incrementMinutesEnd()
{
    time++;
    
    // After 18 runs of this function, trigger dreamcodeFinished and
    // stop running the program.
    if (time >= 18)
    {
        currentState = dreamStates.FINISHED;
        dispatchEvent(dreamcodeFinished);
        time = 0;
        window.clearTimeout(interval);
    }
}

addEventListener("DOMContentLoaded", function()
{
    initKeys();

    addEventListener("keydown", function(event)
    {
        let key = event.key;
        if (key === "A" || key === "B" ) {
            key = key.toLowerCase();
        }
        if (key in keysPressed === false) {
            return;
        }

        keysPressed[key] = true;

        switch(currentState)
        {
            case dreamStates.SILENT:
                // After pressing A, B, return, shift and left
                if (keysPressed["a"] &&
                    keysPressed["b"] &&
                    keysPressed["Enter"] &&
                    keysPressed["Shift"] &&
                    keysPressed["ArrowLeft"])
                {
                    currentState = dreamStates.SILENT_BUTTON1;
                    initKeys();
                }
                
                break;
            
            case dreamStates.SILENT_BUTTON1:
                // After pressing A, B and right
                if (keysPressed["a"] &&
                    keysPressed["b"] &&
                    keysPressed["ArrowRight"])
                {
                    currentState = dreamStates.MUSIC;
                    initKeys();
                    dispatchEvent(dreamcodeMusic);
                }
                
                break;
            
            case dreamStates.MUSIC:
                // After pressing B, shift and right
                if (keysPressed["b"] &&
                    keysPressed["Shift"] &&
                    keysPressed["ArrowRight"])
                {
                    currentState = dreamStates.MUSIC_BUTTON1;
                    initKeys();
                }
                
                break;
            
            case dreamStates.MUSIC_BUTTON1:
                // After pressing B, right and down
                if (keysPressed["b"] &&
                    keysPressed["ArrowRight"] &&
                    keysPressed["ArrowDown"])
                {
                    currentState = dreamStates.MESSAGE;
                    initKeys();
                    dispatchEvent(dreamcodeMessage);
                }
                
                break;
            
            case dreamStates.MESSAGE:
                // After pressing A, B and up
                if (keysPressed["a"] &&
                    keysPressed["b"] &&
                    keysPressed["ArrowUp"])
                {
                    currentState = dreamStates.MESSAGE2;
                    initKeys();
                    dispatchEvent(dreamcodeMessage2);
                    window.clearTimeout(interval);
                    interval = window.setInterval(incrementMinutesEnd, INTERVAL_LENGTH);
                }
                
                break;
                
        }
    });
    
    // Keep track of how long the program has been running
    interval = window.setInterval(incrementMinutes, INTERVAL_LENGTH);
});
